"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 极致RTO-硬件故障类
Case Name   : 开启极致RTO，数据插入过程中，备机网卡停止3分钟，数据交易不丢失
Create At   : 2020/01/29
Owner       : @peilinqian
Description :
    1、开启极致RTO
    2、创建表
    3、插入数据
    4、停止DN备机网卡3分钟
    5、校验insert执行结果
    6、校验数据是否有丢失
    7、执行完成后，关闭极致RTO
    8、查询主备数据是否一致
Expect      :
    1、开启极致RTO成功
    2、创建表成功
    3、开始插入大量数据
    4、停止DN备机网卡3分钟成功
    5、校验insert执行成功
    6、校验数据未丢失
    7、执行完成后，关闭极致RTO成功
    8、查询主备数据一致
History     :
    modified：2021-9-3 by 5328113;cfe注入故障返回结果变更，优化断言；
    modified：2021-3-9 by 5328113;主备同步方法调用修改，增加超时等待时间；
    modified 2021-03-01 by @peilinqian；修改获取网卡逻辑
"""

import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.CommonSH import RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class ExtremeRto(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info(
            '----Opengauss_Reliability_RTO_Hardware_Net_Case010:初始化----')

        self.pri_root = Node(node='PrimaryRoot')
        self.pri_dbuser = Node(node='PrimaryDbUser')
        self.sta1_root = Node(node='Standby1Root')
        self.sta1_dbuser = Node(node='Standby1DbUser')
        self.sta2_dbuser = Node(node='Standby2DbUser')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.sta_1_sh = CommonSH('Standby1DbUser')
        self.sta_2_sh = CommonSH('Standby2DbUser')
        self.com = Common()
        self.constant = Constant()
        self.tpcc_path = macro.TPCC_PATH
        self.t_table_name = 't_RTO_Hardware_Net_Case010'

        self.insert_num = 500
        self.loop_num = 5000
        self.circle_num = 8
        insert_data = ''
        self.create_sql = f'drop table if exists {self.t_table_name};' \
            f'create table {self.t_table_name}(id int, name varchar);'

        for i in range(self.insert_num):
            if i < self.insert_num - 1:
                insert_data = insert_data + f'''({i},'name-{i}'),'''
            if i == self.insert_num - 1:
                insert_data = insert_data + f'''({i},'name-{i}')'''
        self.insert_sql = f'''begin
            for i in 1..{self.loop_num} loop
            insert into {self.t_table_name} values {insert_data};
            end
            loop;
            end;'''

        self.select_sql = f'select count(*) from {self.t_table_name};'
        self.drop_sql = f'drop table {self.t_table_name};'
        self.node_num = self.com.get_node_num(self.pri_root)
        self.log.info(self.node_num)
        self.max_time = 1200
        self.min_time = 300

    def test_main(self):
        try:
            self.log.info('----1、开启极致RTO----')
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'replication_type=1')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_parse_workers=4')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_redo_workers=4')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'hot_standby=off')
            self.assertTrue(msg)
            # 重启数据库配置文件生效
            self.pri_sh.stopDbCluster()
            time.sleep(2)
            self.pri_sh.startDbCluster()

            self.log.info('----查看主机query，同步是否正常----')
            self.pri_sh.check_location_consistency('primary',
                                                   self.node_num,
                                                   self.min_time)
            self.log.info('----查询主备状态----')
            status = self.pri_sh.getDbClusterStatus('status')
            self.assertTrue(status)

            self.log.info("----2、创建表----")
            create_result = self.pri_sh.executDbSql(self.create_sql)
            self.log.info(create_result)
            self.assertIn(self.constant.CREATE_TABLE_SUCCESS, create_result)

            self.log.info("----3、插入数据----")
            insert_thread = ComThread(self.pri_sh.cycle_exec_sql,
                                      args=(self.insert_sql, self.circle_num))
            insert_thread.setDaemon(True)
            insert_thread.start()

            self.log.info('----3、停止DN备机网卡3分钟----')
            self.log.info('----获取网卡----')
            network_card_cmd = 'ifconfig'
            self.log.info(network_card_cmd)
            network_card_result = self.sta1_root.sh(network_card_cmd).result()
            network_card_list = network_card_result.split('\n\n')
            self.log.info(network_card_list)
            network_card = ''
            for network_card_item in network_card_list:
                if self.sta1_dbuser.db_host in network_card_item:
                    network_card = network_card_item.split(':')[0].strip()
                    self.log.info(network_card)

            self.log.info('----注入故障----')
            start_time = time.time()
            inject_cmd = f'rNet_down (dev, time)values({network_card}, 180)'
            self.log.info(inject_cmd)
            inject_result = self.com.cfe_inject(self.sta1_root, inject_cmd)
            self.log.info(inject_result)
            self.assertIn(self.constant.cfe_inject_netdown_success_msg,
                          inject_result)
            # 等待备机故障注入完成
            end_time = time.time()
            self.log.info("start_time:" + str(start_time) +
                          ";end_time:" + str(end_time))
            if end_time - start_time < 180:
                time.sleep(180 - end_time + start_time)

            self.log.info("----5、校验insert执行结果----")
            insert_thread.join()
            insert_result = insert_thread.get_result()
            self.assertTrue(insert_result)

            self.log.info('----查看主机query，同步是否正常----')
            self.pri_sh.check_location_consistency('primary',
                                                   self.node_num,
                                                   self.min_time)
            self.log.info("----6、校验数据是否有丢失----")
            select_result = self.pri_sh.executDbSql(self.select_sql)
            self.log.info(select_result)
            suc_flag = str(self.loop_num * self.insert_num * self.circle_num)
            self.assertIn(suc_flag, select_result)

        finally:
            self.log.info('----7、执行完成后，关闭极致RTO----')
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_parse_workers = 1')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'recovery_redo_workers = 1')
            self.assertTrue(msg)
            msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'hot_standby=on')
            self.assertTrue(msg)
            # 重启数据库配置文件生效
            self.pri_sh.stopDbCluster()
            time.sleep(2)
            self.pri_sh.startDbCluster()

            # 校验备机是否完成数据同步
            self.log.info('校验备机是否完成数据同步')
            flag_1 = self.sta_1_sh.check_location_consistency('standby',
                                                              self.node_num,
                                                              self.min_time)
            self.assertTrue(flag_1)
            flag_2 = self.sta_2_sh.check_location_consistency('standby',
                                                              self.node_num,
                                                              self.min_time)
            self.assertTrue(flag_2)

            self.log.info('----8、查询主备数据是否一致----')
            nodes_tuple = (self.pri_dbuser,
                           self.sta1_dbuser,
                           self.sta2_dbuser)
            select_sql = f'select count(*) from {self.t_table_name};'
            flag = self.com.check_data_sample_by_all(select_sql, *nodes_tuple)
            self.assertTrue(flag)

    def tearDown(self):
        self.log.info("----清理测试数据----")
        drop_result = self.pri_sh.executDbSql(self.drop_sql)
        self.log.info(drop_result)

        self.log.info('----查看主机query，同步是否正常----')
        self.pri_sh.check_location_consistency('primary',
                                               self.node_num,
                                               self.min_time)
        self.log.info(
            '----Opengauss_Reliability_RTO_Hardware_Net_Case010:结束----')
